package data

import (
	"bytes"
	"fmt"
	"gitchina/kly_service/util"
	"strconv"
	"time"

	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

type CarrierPubDto struct {
	Id                int     `orm:"pk;auto;column(id)"`
	MemberId          int     `orm:"column(member_id)"`
	SrcProvince       int     `orm:"column(src_province)"`
	SrcCity           int     `orm:"column(src_city)"`
	SrcCounty         int     `orm:"column(src_county)"`
	DestProvince      int     `orm:"column(dest_province)"`
	DestCity          int     `orm:"column(dest_city)"`
	DestCounty        int     `orm:"column(dest_county)"`
	Price             float32 `orm:"column(price)"`
	ShipmentTime      string  `orm:"column(shipment_time)"`
	State             int     `orm:"column(state)"`
	VehicleType       int     `orm:"column(vehicle_type)"`
	VehicleLen        int     `orm:"column(vehicle_len)"`
	VehicleLoad       int     `orm:"column(vehicle_load)"`
	SrcGeo            string  `orm:"column(src_geo)"`
	DestGeo           string  `orm:"column(dest_geo)"`
	SrcLocationTitle  string  `orm:"column(src_location_title)"`
	DestLocationTitle string  `orm:"column(dest_location_title)"`
	SrcLocation       string  `orm:column(src_location)`
	DestLocation      string  `orm:"column(dest_location)"`
	Type              int     `orm:"column(type)"`
}

type QueryCarrierPubListParam struct {
	StartArea   int
	EndArea     int
	TimeBegin   string
	TimeEnd     string
	VehicleType string
	VehicleLen  string
	VehicleLoad string
	Type        int
	PageNo      int
	PageSize    int
}

type QueryCarrierParam struct {
	VehicleType       string
	VehicleLen        string
	VehicleLoad       string
	FrequentLineStart string
	FrequentLineEnd   string
	PageNo            int
	PageSize          int
	Type              int
}

type CarrierPubDetail struct {
	Name              string  `orm:"column(name)"`
	OwnerPhone        string  `orm:"column(phone)"`
	OwnerStars        int     `orm:"column(stars)"`
	CarrierPubId      int     `orm:"column(pub_id)"`
	MemberId          int     `orm:"column(member_id)"`
	SrcProvince       int     `orm:"column(src_province)"`
	SrcCity           int     `orm:"column(src_city)"`
	SrcCounty         int     `orm:"column(src_county)"`
	DestProvince      int     `orm:"column(dest_province)"`
	DestCity          int     `orm:"column(dest_city)"`
	DestCounty        int     `orm:"column(dest_county)"`
	Price             float32 `orm:"column(price)"`
	ShipmentTime      string  `orm:"column(shipment_time)"`
	VehicleType       string  `orm:"column(vehicle_type)"`
	VehicleLen        string  `orm:"column(vehicle_len)"`
	VehicleLoad       string  `orm:"column(vehicle_load)"`
	VehicleNo         string  `orm:"column(vehicle_No)"`
	SrcGeo            string  `orm:"column(src_geo)"`
	DestGeo           string  `orm:"column(dest_geo)"`
	SrcLocationTitle  string  `orm:"column(src_location_title)"`
	DestLocationTitle string  `orm:"column(dest_location_title)"`
	SrcLocation       string  `orm:"column(src_location)"`
	DestLocation      string  `orm:"column(dest_location)"`
	MemberPhotoUrl    string  `orm:"column(photo)"`
	FrequentLineStart string  `orm:"column(frequent_line_start)"`
	FrequentLineEnd   string  `orm:"column(frequent_line_end)"`
	Type              int     `orm:"column(type)"`
}

type CarrierPubListDto struct {
	OwnerName         string  `orm:"column(name)"`
	OwnerPhone        string  `orm:"column(phone)"`
	OwnerStars        int     `orm:"column(stars)"`
	OwnerId           int     `orm:"column(member_id)"`
	CarrierPubId      int     `orm:"column(pub_id)"`
	SrcProvince       int     `orm:"column(src_province)"`
	SrcCity           int     `orm:"column(src_city)"`
	SrcCounty         int     `orm:"column(src_county)"`
	DestProvince      int     `orm:"column(dest_province)"`
	DestCity          int     `orm:"column(dest_city)"`
	DestCounty        int     `orm:"column(dest_county)"`
	Price             float32 `orm:"column(price)"`
	ShipmentTime      string  `orm:"column(shipment_time)"`
	VehicleType       string  `orm:"column(vehicle_type)"`
	VehicleLen        string  `orm:"column(vehicle_len)"`
	VehicleLoad       string  `orm:"column(vehicle_load)"`
	VehiclePhotoUrl   string  `orm:"column(vehicle_photo)"`
	SrcGeo            string  `orm:"column(src_geo)"`
	DestGeo           string  `orm:"column(dest_geo)"`
	SrcLocationTitle  string  `orm:"column(src_location_title)"`
	DestLocationTitle string  `orm:"column(dest_location_title)"`
	SrcLocation       string  `orm:column(src_location)`
	DestLocation      string  `orm:"column(dest_location)"`
	Type              int     `orm:"column(type)"`
}

type CarrierListDto struct {
	OwnerName         string `orm:"column(name)"`
	OwnerId           int    `orm:"column(member_id)"`
	AuthState         int    `orm:"column(auth_state)"`
	VehicleType       string `orm:"column(vehicle_type)"`
	VehicleLen        string `orm:"column(vehicle_len)"`
	VehicleLoad       string `orm:"column(vehicle_load)"`
	VehiclePhotoUrl   string `orm:"column(vehicle_photo)"`
	FrequentLineStart string `orm:"column(frequent_line_start)"`
	FrequentLineEnd   string `orm:"column(frequent_line_end)"`
	CreateTime        string `orm:"column(create_time)"`
	Photo             string `orm:"column(photo)"`
	Phone             string `orm:"column(phone)"`
	ScoreTotal        int    `orm:"column(score_total)"`
	ScoreCount        int    `orm:"column(score_count)"`
	Type              int    `orm:"column(type)"`
}

func init() {
	orm.RegisterModel(new(CarrierPubDto))
}

func (c *CarrierPubDto) TableName() string {
	return "l_carrier_pub"
}

func (l LogisticsRepo) AddCarrierPub(dto *CarrierPubDto) (id int64, err error) {
	var num int64
	var list orm.ParamsList
	o := orm.NewOrm()
	if num, err = o.Raw(SQL_Mbr_Get_Vehicle_Info, dto.MemberId).ValuesFlat(&list); err == nil {
		if num > 0 {
			dto.VehicleType, err = strconv.Atoi(list[0].(string))
			dto.VehicleLen, err = strconv.Atoi(list[2].(string))
			id, err = o.Insert(dto)
		}
	}
	return
}

func (l LogisticsRepo) UpdateCarrierPub(pub *CarrierPubDto) error {
	o := orm.NewOrm()
	_, err := o.Raw(SQL_Logis_Upd_Carrier_Pub, pub.SrcProvince, pub.SrcCity, pub.SrcCounty,
		pub.DestProvince, pub.DestCity, pub.DestCounty, pub.Price, pub.ShipmentTime,
		pub.VehicleLoad, pub.SrcGeo, pub.DestGeo, pub.SrcLocationTitle, pub.DestLocationTitle, pub.SrcLocation, pub.DestLocation, pub.Id, pub.MemberId).Exec()
	return err
}

func (l LogisticsRepo) CancelCarrierPub(memberId, carrierPubId int) (err error) {
	o := orm.NewOrm()
	_, err = o.Raw(SQL_Logis_Cancel_Carrier_Pub, carrierPubId, memberId).Exec()
	return
}

func (l LogisticsRepo) GetCarrierPub(memberId int) (pub CarrierPubDto, err error) {
	o := orm.NewOrm()
	err = o.Raw(SQL_Logis_Get_Carrier_Pub, memberId).QueryRow(&pub)
	return pub, err
}

func (l LogisticsRepo) GetCarrierPubCount(memberId int) (count int, err error) {
	var num int64
	var list orm.ParamsList
	o := orm.NewOrm()
	if num, err = o.Raw(SQL_Logis_Carrier_Pub_Count, memberId).ValuesFlat(&list); err == nil {
		if num > 0 {
			count, err = strconv.Atoi(list[0].(string))
		}
	}
	return
}

func (l LogisticsRepo) GetActiveCarrierPub(memberId int) ([]CarrierPubDto, error) {
	var list []CarrierPubDto
	o := orm.NewOrm()
	_, err := o.Raw(SQL_Logis_Get_Active_Carrier_Pub, memberId).QueryRows(&list)
	return list, err
}

func (l LogisticsRepo) GetCarrierPubHistory(memberId int) ([]CarrierPubDto, error) {
	var list []CarrierPubDto
	o := orm.NewOrm()
	_, err := o.Raw(SQL_Logis_Get_Carrier_Pub_History, memberId).QueryRows(&list)
	return list, err
}

func (l LogisticsRepo) QueryCarrierPubList(param QueryCarrierPubListParam) ([]CarrierPubListDto, int, error) {
	var num int64
	var rowCount int
	var err error
	var list []CarrierPubListDto
	var flat orm.ParamsList
	o := orm.NewOrm()
	format, args := l.getQueryCarrierPubListCond(param, false)
	countFormat, countArgs := l.getQueryCarrierPubListCond(param, true)
	if num, err = o.Raw(fmt.Sprintf(SQL_Logis_Get_Carrier_Pub_List, format), args).QueryRows(&list); num >= 1 {
		if num, err = o.Raw(fmt.Sprintf(SQL_Logis_Get_Carrier_Pub_List_Count, countFormat), countArgs).ValuesFlat(&flat); num >= 1 {
			rowCount, err = strconv.Atoi(flat[0].(string))
			util.GetLogger().Debug("[data-QueryCarrierPubList] - debug:rowcount::%s", flat[0])
		}
	}
	return list, rowCount, err
}

func (l LogisticsRepo) QueryCarrierList(param QueryCarrierParam) ([]CarrierListDto, int, error) {
	var num int64
	var rowCount int
	var err error
	var list []CarrierListDto
	var flat orm.ParamsList
	o := orm.NewOrm()
	format, args := l.getQueryCarriersCond(param, false)
	countFormat, countArgs := l.getQueryCarriersCond(param, true)
	if num, err = o.Raw(fmt.Sprintf(SQL_Logis_Get_Carrier_List, format), args).QueryRows(&list); num >= 1 {
		if num, err = o.Raw(fmt.Sprintf(SQL_Logis_Get_Carrier_List_Count, countFormat), countArgs).ValuesFlat(&flat); num >= 1 {
			rowCount, err = strconv.Atoi(flat[0].(string))
			util.GetLogger().Debug("[data.QueryCarrierList] - debug:rowcount::%s", flat[0])
		}
	}
	return list, rowCount, err
}

func (l LogisticsRepo) GetCarrierTotalCount() (count int, err error) {
	var num int64
	var flat orm.ParamsList
	o := orm.NewOrm()
	if num, err = o.Raw(fmt.Sprintf(SQL_Logis_Get_Carrier_List_Count, "")).ValuesFlat(&flat); num >= 1 {
		count, err = strconv.Atoi(flat[0].(string))
		util.GetLogger().Debug("[data.GetCarriersTotalCount] - debug:rowcount::%s", flat[0])
	}
	return
}

func (l LogisticsRepo) GetCarrierPubDetail(pubId int) (CarrierPubDetail, error) {
	var detail CarrierPubDetail
	o := orm.NewOrm()
	err := o.Raw(SQL_Logis_Get_Carrier_Pub_Detail, pubId).QueryRow(&detail)
	return detail, err
}

func (l LogisticsRepo) ActiveExpiredCarrier() error {
	o := orm.NewOrm()
	_, err := o.Raw(SQL_Logis_Active_Expired_Carrier, time.Now().AddDate(0, 0, -7)).Exec()
	return err
}

func (r LogisticsRepo) getQueryCarrierPubListCond(param QueryCarrierPubListParam, ignoreLimit bool) (string, []interface{}) {
	var buffer bytes.Buffer
	var args = make([]interface{}, 0)
	if param.StartArea != 0 {
		if param.StartArea%10000 == 0 {
			buffer.WriteString(" AND src_province = ?")
		} else if param.StartArea%100 == 0 {
			buffer.WriteString(" AND src_city = ?")
		} else {
			buffer.WriteString(" AND src_county = ?")
		}
		args = append(args, param.StartArea)
	}
	if param.EndArea != 0 {
		if param.EndArea%10000 == 0 {
			buffer.WriteString(" AND dest_province = ?")
		} else if param.EndArea%100 == 0 {
			buffer.WriteString(" AND dest_city = ?")
		} else {
			buffer.WriteString(" AND dest_county = ?")
		}
		args = append(args, param.EndArea)
	}

	if param.VehicleLen != "" {
		buffer.WriteString(" AND p.vehicle_len = ?")
		args = append(args, param.VehicleLen)
	}

	if param.VehicleLoad != "" {
		buffer.WriteString(" AND p.vehicle_load = ?")
		args = append(args, param.VehicleLoad)
	}

	if param.VehicleType != "" {
		buffer.WriteString(" AND p.vehicle_type = ?")
		args = append(args, param.VehicleType)
	}

	buffer.WriteString(" AND p.type = ?")
	args = append(args, param.Type)

	var time_begin string
	var time_end string
	if param.TimeBegin == "" {
		time_begin = time.Now().Format("2006-01-02 15:04:05")
	} else {
		time_begin = param.TimeBegin
	}

	if param.TimeEnd == "" {
		time_end = time.Now().AddDate(0, 1, 1).Format("2006-01-02 00:00:00")
	} else {
		time_end = param.TimeEnd
	}

	buffer.WriteString(" AND shipment_time >= ?")
	buffer.WriteString(" AND shipment_time <= ?")
	if !ignoreLimit {
		buffer.WriteString(fmt.Sprintf(" ORDER BY p.id DESC LIMIT %d, %d", (param.PageNo-1)*param.PageSize, param.PageSize))
	}
	args = append(args, time_begin, time_end)

	return buffer.String(), args
}

func (r LogisticsRepo) getQueryCarriersCond(param QueryCarrierParam, ignoreLimit bool) (string, []interface{}) {
	var buffer bytes.Buffer
	var args = make([]interface{}, 0)

	if param.VehicleLen != "" {
		buffer.WriteString(" AND p.vehicle_len = ?")
		args = append(args, param.VehicleLen)
	}

	if param.VehicleLoad != "" {
		buffer.WriteString(" AND p.vehicle_load = ?")
		args = append(args, param.VehicleLoad)
	}

	if param.VehicleType != "" {
		buffer.WriteString(" AND p.vehicle_type = ?")
		args = append(args, param.VehicleType)
	}

	buffer.WriteString(" AND m.type_id = ?")
	args = append(args, param.Type)

	if param.FrequentLineStart != "" {
		buffer.WriteString(" AND p.frequent_line_start LIKE '%" + param.FrequentLineStart + "%'")
	}

	if param.FrequentLineEnd != "" {
		buffer.WriteString(" AND p.frequent_line_end LIKE '%" + param.FrequentLineEnd + "%'")
	}

	if !ignoreLimit {
		buffer.WriteString(fmt.Sprintf(" ORDER BY p.id DESC LIMIT %d, %d", (param.PageNo-1)*param.PageSize, param.PageSize))
	}

	return buffer.String(), args
}
